﻿#include <Windows.h>
#include <thread>
#include <string>
#include "vs.h"
#include "../cs2 dumper/offsets.hpp"
#include "../cs2 dumper/client_dll.hpp"
#include "../Settings/Settings.h"
#include "../PlayerData/PlayerData.h"

namespace vs {
    int desiredFOV = 90;

    bool IsValidPtr(void* ptr) {
        return ptr != nullptr && !IsBadReadPtr(ptr, sizeof(ptr));
    }

    std::uintptr_t GetBaseEntity(int index, std::uintptr_t client) {
        auto entListBase = *reinterpret_cast<std::uintptr_t*>(client + cs2_dumper::offsets::client_dll::dwEntityList);
        if (!IsValidPtr((void*)entListBase)) return 0;

        auto entityListbase = *reinterpret_cast<std::uintptr_t*>(entListBase + 0x8 * (index >> 9) + 0x10);
        if (!IsValidPtr((void*)entityListbase)) return 0;

        return *reinterpret_cast<std::uintptr_t*>(entityListbase + 0x78 * (index & 0x1FF));
    }

    void RemoveScope(std::uintptr_t localPlayer) {
        if (IsValidPtr((void*)localPlayer)) {
            auto scopePtr = reinterpret_cast<bool*>(localPlayer + cs2_dumper::schemas::client_dll::C_CSPlayerPawn::m_bIsScoped);
            if (IsValidPtr((void*)scopePtr) && *scopePtr) {
                *scopePtr = false;
            }
            Sleep(0);
        }
    }

    void VisualsThread(std::uintptr_t client) {
        bool fovReset = false; // 添加标志位来跟踪是否已经重置过FOV
        while (true) {
            if (!all_settings::visual::ESP)
            {
                Sleep(20);
                continue;
            }
            auto& playerDataManager = PlayerDataManager::GetInstance();
            auto localPlayer = playerDataManager.GetLocalPlayerData();
            if (!localPlayer.pawn || localPlayer.health <= 0 || localPlayer.team <= 0) {
                Sleep(20);
                continue;
            }

            // --- Zoom Level and Weapon Check ---
            int zoomLevel = 0;
            bool isExcludedWeapon = false;
            auto weaponServices = *reinterpret_cast<std::uintptr_t*>(localPlayer.pawn + cs2_dumper::schemas::client_dll::C_BasePlayerPawn::m_pWeaponServices);
            if (IsValidPtr((void*)weaponServices)) {
                auto activeWeaponHandle = *reinterpret_cast<uint32_t*>(weaponServices + cs2_dumper::schemas::client_dll::CPlayer_WeaponServices::m_hActiveWeapon);
                if (activeWeaponHandle != 0xFFFFFFFF) {
                    auto activeWeapon = GetBaseEntity(activeWeaponHandle & 0x7FFF, client);
                    if (IsValidPtr((void*)activeWeapon)) {
                        uint16_t weapon_id = *reinterpret_cast<uint16_t*>(activeWeapon + cs2_dumper::schemas::client_dll::C_EconEntity::m_AttributeManager + cs2_dumper::schemas::client_dll::C_AttributeContainer::m_Item + cs2_dumper::schemas::client_dll::C_EconItemView::m_iItemDefinitionIndex);
                        // Exclude knives and C4
                        std::vector<uint16_t> excludedWeapons = {
                            49, // C4
                            41, 42, 43, 44, 45, 46, 47, 48, 59, 500, 505, 506, 507, 508, 509, 512, 514, 515, 516, 517, 518, 519, 520, 522, 523, 525 // Knives
                        };
                        isExcludedWeapon = std::find(excludedWeapons.begin(), excludedWeapons.end(), weapon_id) != excludedWeapons.end();
                        if (!isExcludedWeapon) {
                            zoomLevel = *reinterpret_cast<int*>(activeWeapon + cs2_dumper::schemas::client_dll::C_CSWeaponBaseGun::m_zoomLevel);
                        }
                        Sleep(0);
                    }
                }
            }
            if (all_settings::visual::local::self::player_fov && zoomLevel == 0)
            {
                fovReset = false;
                auto cameraServices = *reinterpret_cast<std::uintptr_t*>(localPlayer.pawn + cs2_dumper::schemas::client_dll::C_BasePlayerPawn::m_pCameraServices);
                if (IsValidPtr((void*)cameraServices)) {
                    int* fovPtr = reinterpret_cast<int*>(cameraServices + cs2_dumper::schemas::client_dll::CCSPlayerBase_CameraServices::m_iFOV);
                    if (IsValidPtr((void*)fovPtr))
                    {
                        *fovPtr = all_settings::visual::local::self::player_fov_fw;
                    }
                }
            }
            // 当player_fov关闭且尚未重置时，将FOV设置为90
            else if (!all_settings::visual::local::self::player_fov && !fovReset) {
                auto cameraServices = *reinterpret_cast<std::uintptr_t*>(localPlayer.pawn + cs2_dumper::schemas::client_dll::C_BasePlayerPawn::m_pCameraServices);
                if (IsValidPtr((void*)cameraServices)) {
                    int* fovPtr = reinterpret_cast<int*>(cameraServices + cs2_dumper::schemas::client_dll::CCSPlayerBase_CameraServices::m_iFOV);
                    if (IsValidPtr((void*)fovPtr)) {
                        *fovPtr = desiredFOV;
                        fovReset = true; // 设置标志位，表示已经重置过
                    }
                }
            }

            if (all_settings::visual::local::self::remove_Scoped_blachk && !isExcludedWeapon && (zoomLevel == 1 || zoomLevel == 2)) {
                RemoveScope(localPlayer.pawn);
            }

            if (all_settings::visual::local::self::remove_Scoped_fov) {
                auto cameraServices = *reinterpret_cast<std::uintptr_t*>(localPlayer.pawn + cs2_dumper::schemas::client_dll::C_BasePlayerPawn::m_pCameraServices);
                if (IsValidPtr((void*)cameraServices)) {
                    int* fovPtr = reinterpret_cast<int*>(cameraServices + cs2_dumper::schemas::client_dll::CCSPlayerBase_CameraServices::m_iFOV);

                    if (!isExcludedWeapon) {
                        if (zoomLevel == 1) {
                            *fovPtr = all_settings::visual::local::self::Scoped_fov; // Use adjustable zoomLevel1FOV
                        }
                        else if (zoomLevel == 2) {
                            *fovPtr = all_settings::visual::local::self::Scoped_fov; // Use adjustable zoomLevel2FOV
                        }
                        else if (!all_settings::visual::local::self::player_fov) {
                            *fovPtr = desiredFOV; // Set FOV to menu-defined value for zoomLevel 0
                        }
                    }
                    else if (!all_settings::visual::local::self::player_fov) {
                        *fovPtr = desiredFOV;
                    }

                    Sleep(0);
                }
            }

            // --- NoFlash ---
            if (all_settings::visual::local::world::grenade_settings.removeFlash) {
                float* flash_duration = reinterpret_cast<float*>(localPlayer.pawn  + cs2_dumper::schemas::client_dll::C_CSPlayerPawnBase::m_flFlashDuration);
                if (IsValidPtr((void*)flash_duration) && *flash_duration > 0.0f) {
                    DWORD oldProtect;
                    if (VirtualProtect((LPVOID)flash_duration, sizeof(float), PAGE_EXECUTE_READWRITE, &oldProtect)) {
                        *flash_duration = 0.0f;
                        VirtualProtect((LPVOID)flash_duration, sizeof(float), oldProtect, &oldProtect);
                    }
                }
                Sleep(0);
            }

            // --- NoSmoke ---
            if (all_settings::visual::local::world::grenade_settings.removeSmoke) {
                for (int i = 64; i <= 1024; i++) {
                    auto C_BaseEntity = GetBaseEntity(i, client);
                    if (C_BaseEntity == 0) continue;

                    auto temp_1 = *reinterpret_cast<std::uintptr_t*>(C_BaseEntity + 0x10);
                    if (temp_1 == 0) continue;

                    auto smoke_name = *reinterpret_cast<std::uintptr_t*>(temp_1 + 0x20);
                    if (smoke_name == 0) continue;

                    // Retrieve entity name
                    char ch;
                    std::string entity_name;
                    int maxsize = 64;
                    for (int i_name = 0; i_name < maxsize; i_name++) {
                        ch = *reinterpret_cast<char*>(smoke_name + i_name);
                        if (ch == '\0') break;
                        entity_name += ch;
                    }

                    if (entity_name == "smokegrenade_projectile") {
                        auto m_nSmokeEffectTickBegin = reinterpret_cast<int*>(C_BaseEntity + cs2_dumper::schemas::client_dll::C_SmokeGrenadeProjectile::m_nSmokeEffectTickBegin);
                        if (!m_nSmokeEffectTickBegin) continue;
                        *m_nSmokeEffectTickBegin = 0;

                        auto m_bDidSmokeEffect = reinterpret_cast<bool*>(C_BaseEntity + cs2_dumper::schemas::client_dll::C_SmokeGrenadeProjectile::m_bDidSmokeEffect);
                        if (m_bDidSmokeEffect) *m_bDidSmokeEffect = false;

                        auto m_bSmokeEffectSpawned = reinterpret_cast<bool*>(C_BaseEntity + cs2_dumper::schemas::client_dll::C_SmokeGrenadeProjectile::m_bSmokeEffectSpawned);
                        if (m_bSmokeEffectSpawned) *m_bSmokeEffectSpawned = false;
                    }
                    Sleep(0);
                }
            }
        }
    }

    void Run() {
        const auto client = reinterpret_cast<std::uintptr_t>(GetModuleHandleA("client.dll"));
        if (!client) return;
        std::thread visualsThread(VisualsThread, client);
        visualsThread.detach();
    }
}